#include <iostream>
#include <openssl/sha.h>

#include "content.hpp"
#include "tool.hpp"

using namespace std;

content_t::content_t()
{
	pos = 0;
	cid = 0;
	index = 0;
	type = 0;
	len = 0;
}

bool content_t::open(ifstream& wadstream, uint32_t tmdpos, uint32_t contentpos)
{
	if(!wadstream.is_open())
		return false;
	pos = contentpos;
	wadstream.seekg(tmdpos + 0x01e4);
	cid = get32(wadstream);
	index = get16(wadstream);
	type = get16(wadstream);
	len = get64(wadstream);
	wadstream.read(reinterpret_cast<char*>(hash), sizeof(hash));
	return true;
}

bool content_t::unpack(ifstream& wadstream, string path, uint8_t* titlekey)
{
	if(!wadstream.is_open())
		return false;
	bool ret = true;
	uint8_t* buffer = NULL;
	uint64_t encrypted_len = add_padding(len, 0x10);
	try
	{
		buffer = new uint8_t[encrypted_len];
	}
	catch(exception& e)
	{
		cerr << "Error: " << e.what() << endl;
		return false;
	}
	fill_n(buffer, encrypted_len, 0x00);
	ofstream outfile(path, ios_base::out | ios_base::binary);
	wadstream.seekg(pos);

	wadstream.read(reinterpret_cast<char*>(buffer), encrypted_len);

	if(titlekey != NULL)
	{
		uint8_t iv[16] = {static_cast<uint8_t>(index >> 8),
		                  static_cast<uint8_t>(index),
		                            0x00,0x00,
		                  0x00,0x00,0x00,0x00,
		                  0x00,0x00,0x00,0x00,
		                  0x00,0x00,0x00,0x00};

		aes_cbc_dec(titlekey, iv, buffer, encrypted_len, buffer);

		uint8_t sha1sum[20];
		SHA1(buffer, len, sha1sum);
		for(size_t i=0; i<20; i++)
		{
			if(sha1sum[i] != hash[i])
			{
				cerr << "Content " << index << ": ";
				cerr << "Hash verification failed" << endl;
				ret = false;
				break;
			}
		}

		outfile.write(reinterpret_cast<char*>(buffer), len);
	}
	else
	{
		outfile.write(reinterpret_cast<char*>(buffer), encrypted_len);
	}

	if(outfile.bad())
	{
		cerr << "Something happened trying to write " << path << endl;
		ret = false;
	}

	delete[] buffer;
	outfile.close();

	
	return ret;
}

